package com.aaa.ws.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.aaa.common.util.*;
import com.aaa.ws.entity.User;
import com.aaa.ws.dao.UserDao;
import com.aaa.ws.service.UserService;
import org.apache.shiro.crypto.hash.Sha512Hash;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.aaa.common.vo.Page;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2023-07-03 10:36:55
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;

    //依赖注入  spring框架封装的Redis连接模板类
    @Resource
    private RedisTemplate redisTemplate;

    //依赖注入  获取redis的token
    @Resource
    private HttpServletRequest request;

    /**
     * 根据手机账号查询用户
     *
     * @param phone
     * @return
     */
    @Override
    public User queryByPhone(String phone) {
        //创建User对象
        User userA = new User();

        //传入手机号
        userA.setPhone(phone);
        //给状态赋值  0为存在状态  1为注销状态
        userA.setStateId(0);

        System.out.println("queryByPhone ---" + phone);
        System.out.println("queryByPhone-->User---" + userA);

        //查询 调用queryAllByLimit方法
        List<User> userAList = userDao.queryAllByLimit(userA);

        System.out.println("queryByPhone---userAList-->" + userAList.toString());
        if (userAList.size() >= 1 && !userAList.isEmpty()) {
            return userAList.get(0);
        }
        return null;
    }

    /**
     * 认证接口(登录接口)
     *
     * @param phone
     * @param password
     * @return
     */
    @Override
    public Result login(String phone, String password) {
        System.out.println("phone--" + phone + "    password--" + password);
        //调用queryByPhone方法查询是否有该对象
        User userA = queryByPhone(phone);
        System.out.println("userA-----" + userA);

        if (userA == null) {
            //用户名或者密码错误，返回错误json
            return new Result(ResultStatus.ERROR.getReturnCode(),
                    ResultStatus.ERROR.getReturnMsg(),
                    "用户名或者密码错误");
        }

        //再次使用密码和盐值进行加密运算
        Sha512Hash sha512Hash = new Sha512Hash(password, userA.getSalt(),
                ConstUtil.CredentialsMatcher.HASH_ITERATIONS);

        //判断账户是否存在且密码是否正确
        if (ObjectUtil.isNotNull(userA) && userA.getPassword().equals(sha512Hash.toString())) {
            HashMap<String, String> payload = new HashMap<>();
            //集合内存入userId name phone
            payload.put("userId", userA.getUserId().toString());
            payload.put("name", userA.getName());
            payload.put("phone", userA.getPhone());

            //生成token 使用jwt 加上phone
            String token = phone + "-" + JwtUtils.generateToken(payload);

            //还要把生成的token存储到redis中 方便后面用来校验token
            //设置redis的key的序列化方式  使用StringRedisSerializer方式时，存储的redis中的就是string字符串
            redisTemplate.setKeySerializer(new StringRedisSerializer());

            //先查询userName+“-”+*****  pattern  支持正则表达式
            Set keys = redisTemplate.keys(phone + "-*");

            //再循环删除，确保redis里面没有该phone的多余token存储
            for (Object key : keys) {
                //删除
                redisTemplate.delete(key);
            }
            //把token放入redis  把token作为key  用户对象做为值  方便后面使用token获取用户信息
            redisTemplate.opsForValue().set(token, userA, 8, TimeUnit.HOURS);
            System.out.println("token-----: " + token);

            //把token返回给前端
            return new Result(ResultStatus.SUCCESS.getReturnCode(),
                    ResultStatus.SUCCESS.getReturnMsg(),
                    token);

        } else {
            //用户名或者密码错误，返回错误json
            return new Result(ResultStatus.ERROR.getReturnCode(),
                    ResultStatus.ERROR.getReturnMsg(),
                    "用户名或者密码错误");
        }

    }


    @Override
    public User checkNum(String phone) {
        return this.userDao.checkNum(phone);
    }

    /**
     * 验证token
     *
     * @param token
     * @return
     */
    @Override
    public boolean checkToken(String token) {
        //设置redis的key的序列化方式  使用StringRedisSerializer方式时，存储的redis中的就是string字符串
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //token = userName + "-"+xxx.xxx.xxx
        //String[] tokenArray = token.split("-");
        String tokenSub = token.substring(token.indexOf("-") + 1);
        System.out.println("tokenSub:----------" + tokenSub);
        //tokenArray[1]  =  xxx.xxx.xxx
        //判断根据JWTUtils判断token是否正确  再判断redis是否存在(是否过期)
        if (JwtUtils.verify(tokenSub) && redisTemplate.hasKey(token)) {
            return true;
        }
        return false;
    }


    /**
     * 通过ID查询单条数据
     *
     * @param userId 主键
     * @return 实例对象
     */
    @Override
    public User queryById(Integer userId) {
        return this.userDao.queryById(userId);
    }

    /**
     * 分页查询
     *
     * @param page 筛选条件
     * @return 查询结果
     */
    @Override
    public PageInfo queryByPage(Page<User> page) {
        //分页操作  分页参数一定要进行传递
        if (page == null || page.getPageNo() == null || page.getPageNo() == 0 || page.getPageSize() == null || page.getPageSize() == 0) {
            //进行业务编写时，可以抛出自定义异常
            throw new CustomException(ResultStatus.PARAM_NOT_EMPTY.getReturnCode(),
                    ResultStatus.PARAM_NOT_EMPTY.getReturnMsg());
        }
        PageHelper.startPage(page.getPageNo(), page.getPageSize());
        //获取查询对象
        User user = page.getData();
        return new PageInfo(userDao.queryAllByLimit(user));
    }

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User insert(User user) {
        System.out.println("user----" + user);

        //生成盐值和UUID
        String salt = UUID.randomUUID().toString();
        String userUuid = salt.replaceAll("-", "");

        //给user属性赋值
        user.setUserUuid(userUuid);
        user.setSalt(salt);
        //使用密码和盐值进行加密运算 生成加盐密码
        String password = new Sha512Hash(user.getPassword(), salt,
                ConstUtil.CredentialsMatcher.HASH_ITERATIONS).toString();
        //给密码赋值
        user.setPassword(password);

        //设置服务门店数量为0
        user.setStoreTotal(0);

        //设置服务次数为0
        user.setServiceTotal(0);

        //设置存在状态 为存在
        user.setStateId(0);
        //设置用户余额为0
        user.setBalance(0.0);

        //设置添加时间
        //时间格式化
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String format = dateFormat.format(new Date());
        user.setCreateDate(format);

        this.userDao.insert(user);
        return user;
    }

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User update(User user) {
        this.userDao.update(user);
        return this.queryById(user.getUserId());
    }

    /**
     * 通过主键删除数据
     *
     * @param userId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer userId) {
        return this.userDao.deleteById(userId) > 0;
    }
}
